#include <iostream>     // std::cout
#include <fstream>      // std::ifstream
#include <stdio.h>
#include <getopt.h>
#include <vector>
#include "mmaplib.h"

using namespace std;

string input_file;
string output_file;
string upper_filename;
std::string extend_name;

static const string description = "\t[option]...\n"
                                  "\t-i\tinput file\n"
                                  "\t-o\toutput file\n"
                                  "\t-h\thelp\n";

const string to_file_str = "\tvoid to_file(const std::string& filename){\n"
                           "        std::ofstream outfile(filename, std::ios::binary);\n"
                           "        for (int i = 0; i < size; ++i)\n"
                           "        {\n"
                           "            outfile << data[i];\n"
                           "        }\n"
                           "        outfile.close();\n"
                           "    }\n";

void usage() {
    cout << description << endl;
}

std::vector<std::string> split(std::string str, const std::string &pattern) {
    std::string::size_type pos;
    std::vector<std::string> result;
    str += pattern;//扩展字符串以方便操作
    auto size = static_cast<int>(str.size());
    for (int i = 0; i < size; i++) {
        pos = str.find(pattern, i);
        if (pos < size) {
            std::string s = str.substr(i, pos - i);
            result.push_back(s);
            i = static_cast<int>(pos + pattern.size() - 1);
        }
    }
    return result;
}

int main(int argc, char *argv[]) {

    int opt;
    while ((opt = getopt(argc, argv, "i:o:h")) != -1) {
        switch (opt) {
            case 'i':
                cout << "input : " << optarg << endl;
                input_file = optarg;
                break;

            case 'o':
                cout << "output : " << optarg << endl;
                output_file = optarg;
                break;

            case 'h':
                usage();
                return 0;

            case ':':
                cerr << "option needs a value" << endl;
                break;

            case '?':
                cerr << "unknow option : " << char(optopt) << endl;
                break;

            default:
                cerr << "options was not given " << char(optopt) << endl;
                exit(-1);
        }
    }

    std::vector<std::string> v = split(input_file, ".");
    extend_name = v.size() >= 2 ? v[v.size() - 1] : "";


    upper_filename = output_file;
    for (int i = 0; i < output_file.length(); ++i) {
        upper_filename[i] = toupper(output_file[i]);
    }


    mmaplib::mmap file_mmap(input_file.c_str());


//    std::ifstream is(input_file, std::ios::binary | std::ios::ate);
    if (file_mmap.is_open()) {
        // 2.get length of file:
//        is.seekg(0, is.end);
        int length = file_mmap.size();
//        is.seekg(0, is.beg);

        // 3.Create buffer
        const char *buffer = file_mmap.data();

        std::cout << "Reading " << length << " bits... \n";
        // 4.read data as a block:
//        is.read(buffer, length);

//        if (file_mmap.is_open())
//            std::cout << "file read successfully.";
//        else
//            std::cout << "error: only " << is.gcount() << " could be read";
//        is.close();

        std::ofstream out_file(output_file + ".h");

        char FILE_MICRO[20];
        sprintf(FILE_MICRO, "#ifndef %s_H\n", upper_filename.c_str());
        std::string start(FILE_MICRO);

        out_file << start;

        sprintf(FILE_MICRO, "#define %s_H\n", upper_filename.c_str());
        std::string define(FILE_MICRO);

        out_file << std::string(define);

        sprintf(FILE_MICRO, "#endif //%s_H\n\n", upper_filename.c_str());
        std::string end(FILE_MICRO);

        out_file << "#include <fstream>\n#include <string>\n";

        out_file << "namespace " + upper_filename << " {\n";

        out_file << "\tconst unsigned char data[] = {";
        for (int i = 0; i < length; ++i) {

            out_file << "0x";
            if ((unsigned int) (unsigned char) buffer[i] > 0x0F) {
                out_file << hex << (unsigned int) (unsigned char) buffer[i];
            } else {
                out_file << "0" << hex << (unsigned int) (unsigned char) buffer[i];
            }
            if (i + 1 < length) {
                out_file << ",";
            }
        }


        out_file << "};\n";
        out_file << "\tconst long size = " + std::to_string(length) + ";\n";

        out_file << "\tconst std::string extend_name = \"" + extend_name + "\";\n";

        out_file << to_file_str;

        out_file << "}\n";
        out_file << end;
        out_file.close();
//        delete[] buffer;
    }
    return 0;
}

